package com.mdinic.blogovi.ctrl;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.joda.time.format.DateTimeFormat;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.roo.addon.web.mvc.controller.finder.RooWebFinder;
import org.springframework.roo.addon.web.mvc.controller.scaffold.RooWebScaffold;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.util.UriUtils;
import org.springframework.web.util.WebUtils;

import com.mdinic.blogovi.model.Blog;
import com.mdinic.blogovi.model.BlogPost;
import com.mdinic.blogovi.model.BlogType;
import com.mdinic.blogovi.model.Person;

@RequestMapping("/blogposts")
@Controller
@RooWebScaffold(path = "blogposts", formBackingObject = BlogPost.class)
@RooWebFinder
public class BlogPostController {

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
    }

    @RequestMapping(method = RequestMethod.POST, produces = "text/html")
    public String create(@Valid BlogPost blogPost, BindingResult bindingResult, Model uiModel,
            HttpServletRequest httpServletRequest) {
        if (bindingResult.hasErrors()) {
            populateEditForm(uiModel, blogPost);
            return "blogposts/create";
        }
        uiModel.asMap().clear();
        blogPost.persist();
        return "redirect:/admin/blogposts/" + encodeUrlPathSegment(blogPost.getId().toString(), httpServletRequest);
    }

    @RequestMapping(params = "form", produces = "text/html")
    public String createForm(Model uiModel) {
        populateEditForm(uiModel, new BlogPost());
        List<String[]> dependencies = new ArrayList<String[]>();
        if (BlogType.countBlogTypes() == 0) {
            dependencies.add(new String[] { "blogtype", "blogtypes" });
        }
        if (Person.countPeople() == 0) {
            dependencies.add(new String[] { "person", "people" });
        }
        if (Blog.countBlogs() == 0) {
            dependencies.add(new String[] { "blog", "blogs" });
        }
        uiModel.addAttribute("dependencies", dependencies);
        return "blogposts/create";
    }

    @RequestMapping(value = "/{id}", produces = "text/html")
    public String show(@PathVariable("id") Long id, Model uiModel) {
        addDateTimeFormatPatterns(uiModel);
        uiModel.addAttribute("blogpost", BlogPost.findBlogPost(id));
        uiModel.addAttribute("itemId", id);
        return "blogposts/show";
    }

    @RequestMapping(produces = "text/html")
    public String list(@RequestParam(value = "page", required = false) Integer page,
            @RequestParam(value = "size", required = false) Integer size, Model uiModel) {
        if (page != null || size != null) {
            int sizeNo = size == null ? 10 : size.intValue();
            final int firstResult = page == null ? 0 : (page.intValue() - 1) * sizeNo;
            uiModel.addAttribute("blogposts", BlogPost.findBlogPostEntries(firstResult, sizeNo));
            float nrOfPages = (float) BlogPost.countBlogPosts() / sizeNo;
            uiModel.addAttribute("maxPages", (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ? nrOfPages + 1
                    : nrOfPages));
        } else {
            uiModel.addAttribute("blogposts", BlogPost.findAllBlogPosts());
        }
        addDateTimeFormatPatterns(uiModel);
        return "blogposts/list";
    }

    @RequestMapping(method = RequestMethod.PUT, produces = "text/html")
    public String update(@Valid BlogPost blogPost, BindingResult bindingResult, Model uiModel,
            HttpServletRequest httpServletRequest) {
        if (bindingResult.hasErrors()) {
            populateEditForm(uiModel, blogPost);
            return "blogposts/update";
        }
        uiModel.asMap().clear();
        blogPost.merge();
        return "redirect:/admin/blogposts/" + encodeUrlPathSegment(blogPost.getId().toString(), httpServletRequest);
    }

    @RequestMapping(value = "/{id}", params = "form", produces = "text/html")
    public String updateForm(@PathVariable("id") Long id, Model uiModel) {
        populateEditForm(uiModel, BlogPost.findBlogPost(id));
        return "blogposts/update";
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE, produces = "text/html")
    public String delete(@PathVariable("id") Long id, @RequestParam(value = "page", required = false) Integer page,
            @RequestParam(value = "size", required = false) Integer size, Model uiModel) {
        BlogPost blogPost = BlogPost.findBlogPost(id);
        blogPost.remove();
        uiModel.asMap().clear();
        uiModel.addAttribute("page", (page == null) ? "1" : page.toString());
        uiModel.addAttribute("size", (size == null) ? "10" : size.toString());
        return "redirect:/admin/blogposts";
    }

    void addDateTimeFormatPatterns(Model uiModel) {
        uiModel.addAttribute("blogPost_posted_date_format",
                DateTimeFormat.patternForStyle("M-", LocaleContextHolder.getLocale()));
        uiModel.addAttribute("blogPost_promoted_date_format",
                DateTimeFormat.patternForStyle("M-", LocaleContextHolder.getLocale()));
    }

    void populateEditForm(Model uiModel, BlogPost blogPost) {
        uiModel.addAttribute("blogPost", blogPost);
        addDateTimeFormatPatterns(uiModel);
        uiModel.addAttribute("blogs", Blog.findAllBlogs());
        uiModel.addAttribute("blogtypes", BlogType.findAllBlogTypes());
        uiModel.addAttribute("people", Person.findAllPeople());
    }

    String encodeUrlPathSegment(String pathSegment, HttpServletRequest httpServletRequest) {
        String enc = httpServletRequest.getCharacterEncoding();
        if (enc == null) {
            enc = WebUtils.DEFAULT_CHARACTER_ENCODING;
        }
        try {
            pathSegment = UriUtils.encodePathSegment(pathSegment, enc);
        } catch (UnsupportedEncodingException uee) {
        }
        return pathSegment;
    }

    @RequestMapping(params = { "find=ByApprovedNot", "form" }, method = RequestMethod.GET)
    public String findBlogPostsByApprovedNotForm(Model uiModel) {
        return "blogposts/findBlogPostsByApprovedNot";
    }

    @RequestMapping(params = "find=ByApprovedNot", method = RequestMethod.GET)
    public String findBlogPostsByApprovedNot(@RequestParam(value = "approved", required = false) Boolean approved,
            Model uiModel) {
        uiModel.addAttribute("blogposts", BlogPost.findBlogPostsByApprovedNot(approved == null).getResultList());

        uiModel.addAttribute("doapprove", approved == null);
        return "blogposts/list";
    }

    @RequestMapping(params = { "find=ByBlog", "form" }, method = RequestMethod.GET)
    public String findBlogPostsByBlogForm(Model uiModel) {
        uiModel.addAttribute("blogs", Blog.findAllBlogs());
        return "blogposts/findBlogPostsByBlog";
    }

    @RequestMapping(params = "find=ByBlog", method = RequestMethod.GET)
    public String findBlogPostsByBlog(@RequestParam("blog") Blog blog, Model uiModel) {
        uiModel.addAttribute("blogposts", BlogPost.findBlogPostsByBlog(blog).getResultList());
        return "blogposts/list";
    }

    @RequestMapping(params = { "find=ByDescriptionEquals", "form" }, method = RequestMethod.GET)
    public String findBlogPostsByDescriptionEqualsForm(Model uiModel) {
        return "blogposts/findBlogPostsByDescriptionEquals";
    }

    @RequestMapping(params = "find=ByDescriptionEquals", method = RequestMethod.GET)
    public String findBlogPostsByDescriptionEquals(@RequestParam("description") String description, Model uiModel) {
        uiModel.addAttribute("blogposts", BlogPost.findBlogPostsByDescriptionEquals(description).getResultList());
        return "blogposts/list";
    }

    @RequestMapping(params = { "find=ByHeadlineEquals", "form" }, method = RequestMethod.GET)
    public String findBlogPostsByHeadlineEqualsForm(Model uiModel) {
        return "blogposts/findBlogPostsByHeadlineEquals";
    }

    @RequestMapping(params = "find=ByHeadlineEquals", method = RequestMethod.GET)
    public String findBlogPostsByHeadlineEquals(@RequestParam("headline") String headline, Model uiModel) {
        uiModel.addAttribute("blogposts", BlogPost.findBlogPostsByHeadlineEquals(headline).getResultList());
        return "blogposts/list";
    }

    @RequestMapping(params = { "find=ByPerson", "form" }, method = RequestMethod.GET)
    public String findBlogPostsByPersonForm(Model uiModel) {
        uiModel.addAttribute("people", Person.findAllPeople());
        return "blogposts/findBlogPostsByPerson";
    }

    @RequestMapping(params = "find=ByPerson", method = RequestMethod.GET)
    public String findBlogPostsByPerson(@RequestParam("person") Person person, Model uiModel) {
        uiModel.addAttribute("blogposts", BlogPost.findBlogPostsByPerson(person).getResultList());
        return "blogposts/list";
    }

    @RequestMapping(params = { "find=ByUrlEquals", "form" }, method = RequestMethod.GET)
    public String findBlogPostsByUrlEqualsForm(Model uiModel) {
        return "blogposts/findBlogPostsByUrlEquals";
    }

    @RequestMapping(params = "find=ByUrlEquals", method = RequestMethod.GET)
    public String findBlogPostsByUrlEquals(@RequestParam("url") String url, Model uiModel) {
        uiModel.addAttribute("blogposts", BlogPost.findBlogPostsByUrlEquals(url).getResultList());
        return "blogposts/list";
    }

    @RequestMapping(params = { "find=ByPromotedIsNotNull", "form" }, method = RequestMethod.GET)
    public String findBlogPostsByPromotedIsNotNullForm() {
        return "blogposts/findBlogPostsByPromotedIsNotNull";
    }

    @RequestMapping(params = "find=ByPromotedIsNotNull", method = RequestMethod.GET)
    public String findBlogPostsByPromotedIsNotNull(Model uiModel) {
        uiModel.addAttribute("blogposts", BlogPost.findBlogPostsByPromotedIsNotNull().getResultList());
        return "blogposts/list";
    }

    @RequestMapping(params = { "find=ByPromotedIsNull", "form" }, method = RequestMethod.GET)
    public String findBlogPostsByPromotedIsNullForm() {
        return "blogposts/findBlogPostsByPromotedIsNull";
    }

    @RequestMapping(params = "find=ByPromotedIsNull", method = RequestMethod.GET)
    public String findBlogPostsByPromotedIsNull(Model uiModel) {
        uiModel.addAttribute("dopromote", true);
        uiModel.addAttribute("blogposts", BlogPost.findBlogPostsByPromotedIsNull().getResultList());
        return "blogposts/list";
    }

    @RequestMapping(value = "/{id}", params = { "Approve", "form" }, produces = "text/html", method = RequestMethod.GET)
    public String approve(@PathVariable("id") Long id, Model uiModel) {
        BlogPost post = BlogPost.findBlogPost(id);
        post.setApproved(true);
        post.merge();

        uiModel.addAttribute("blogposts", BlogPost.findBlogPostsByApprovedNot(true).getResultList());
        uiModel.addAttribute("doapprove", true);
        return "blogposts/list";
    }

    @RequestMapping(value = "/{id}", params = { "Promote", "form" }, produces = "text/html", method = RequestMethod.GET)
    public String promote(@PathVariable("id") Long id, Model uiModel) {
        BlogPost post = BlogPost.findBlogPost(id);
        post.setPromoted(new Date());
        post.merge();

        uiModel.addAttribute("dopromote", true);
        uiModel.addAttribute("blogposts", BlogPost.findBlogPostsByPromotedIsNull().getResultList());
        return "blogposts/list";
    }
}
